From: Rui Matos Date: Thu, 29 May 2014 16:42:46 +0000 (+0200) Subject: status/keyboard: Factor out an InputSourceManager class X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~1013^2^2~2152 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=effe6fab3a97d60f14a585e8083b332f58893c25;p=gnome-shell.git status/keyboard: Factor out an InputSourceManager class https://bugzilla.gnome.org/show_bug.cgi?id=736435 --- diff --git a/js/ui/status/keyboard.js b/js/ui/status/keyboard.js index 990021b70..56752fd03 100644 --- a/js/ui/status/keyboard.js +++ b/js/ui/status/keyboard.js @@ -147,25 +147,10 @@ const InputSourceSwitcher = new Lang.Class({ } }); -const InputSourceIndicator = new Lang.Class({ - Name: 'InputSourceIndicator', - Extends: PanelMenu.Button, +const InputSourceManager = new Lang.Class({ + Name: 'InputSourceManager', _init: function() { - this.parent(0.0, _("Keyboard")); - - this._container = new Shell.GenericContainer(); - this._container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth)); - this._container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight)); - this._container.connect('allocate', Lang.bind(this, this._containerAllocate)); - - this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' }); - this._hbox.add_child(this._container); - this._hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM)); - - this.actor.add_child(this._hbox); - this.actor.add_style_class_name('panel-status-button'); - // All valid input sources currently in the gsettings // KEY_INPUT_SOURCES list indexed by their index there this._inputSources = {}; @@ -197,29 +182,16 @@ const InputSourceIndicator = new Lang.Class({ this._xkbInfo = KeyboardManager.getXkbInfo(); - this._propSeparator = new PopupMenu.PopupSeparatorMenuItem(); - this.menu.addMenuItem(this._propSeparator); - this._propSection = new PopupMenu.PopupMenuSection(); - this.menu.addMenuItem(this._propSection); - this._propSection.actor.hide(); - this._ibusReady = false; this._ibusManager = IBusManager.getIBusManager(); this._ibusManager.connect('ready', Lang.bind(this, this._ibusReadyCallback)); this._ibusManager.connect('properties-registered', Lang.bind(this, this._ibusPropertiesRegistered)); this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated)); - this._inputSourcesChanged(); this._keyboardManager = KeyboardManager.getKeyboardManager(); global.display.connect('modifiers-accelerator-activated', Lang.bind(this, this._modifiersSwitcher)); - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout)); - - Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated)); - this._sessionUpdated(); - this._sourcesPerWindow = false; this._focusWindowNotifyId = 0; this._overviewShowingId = 0; @@ -228,12 +200,8 @@ const InputSourceIndicator = new Lang.Class({ this._sourcesPerWindowChanged(); }, - _sessionUpdated: function() { - // re-using "allowSettings" for the keyboard layout is a bit shady, - // but at least for now it is used as "allow popping up windows - // from shell menus"; we can always add a separate sessionMode - // option if need arises. - this._showLayoutItem.actor.visible = Main.sessionMode.allowSettings; + reload: function() { + this._inputSourcesChanged(); }, _ibusReadyCallback: function(im, ready) { @@ -288,7 +256,6 @@ const InputSourceIndicator = new Lang.Class({ }, _currentInputSourceChanged: function() { - let nVisibleSources = Object.keys(this._inputSources).length; let newSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE); let newSource = this._inputSources[newSourceIndex]; @@ -300,25 +267,11 @@ const InputSourceIndicator = new Lang.Class({ oldSource.indicatorLabel.hide(); } - if (!newSource || (nVisibleSources < 2 && !newSource.properties)) { - // This source index might be invalid if we weren't able - // to build a menu item for it, so we hide ourselves since - // we can't fix it here. *shrug* - - // We also hide if we have only one visible source unless - // it's an IBus source with properties. - this.menu.close(); - this.actor.hide(); - return; - } - - this.actor.show(); + this.emit('current-source-changed'); newSource.menuItem.setOrnament(PopupMenu.Ornament.DOT); newSource.indicatorLabel.show(); - this._buildPropSection(newSource.properties); - for (let i = 1; i < this._mruSources.length; ++i) if (this._mruSources[i] == newSource) { let currentSource = this._mruSources.splice(i, 1); @@ -384,20 +337,17 @@ const InputSourceIndicator = new Lang.Class({ this._ibusSources[is.id] = is; } - let menuIndex = 0; for (let i in this._inputSources) { let is = this._inputSources[i]; if (inputSourcesByShortName[is.shortName].length > 1) { let sub = inputSourcesByShortName[is.shortName].indexOf(is) + 1; is.shortName += String.fromCharCode(0x2080 + sub); } - - this.menu.addMenuItem(is.menuItem, menuIndex++); - is.indicatorLabel.hide(); - this._container.add_actor(is.indicatorLabel); } + this.emit('sources-changed'); + let sourcesList = []; for (let i in this._inputSources) sourcesList.push(this._inputSources[i]); @@ -416,33 +366,6 @@ const InputSourceIndicator = new Lang.Class({ this._currentInputSourceChanged(); }, - _showLayout: function() { - Main.overview.hide(); - - let source = this._currentSource; - let xkbLayout = ''; - let xkbVariant = ''; - - if (source.type == INPUT_SOURCE_TYPE_XKB) { - [, , , xkbLayout, xkbVariant] = this._xkbInfo.get_layout_info(source.id); - } else if (source.type == INPUT_SOURCE_TYPE_IBUS) { - let engineDesc = this._ibusManager.getEngineDesc(source.id); - if (engineDesc) { - xkbLayout = engineDesc.get_layout(); - xkbVariant = ''; - } - } - - if (!xkbLayout || xkbLayout.length == 0) - return; - - let description = xkbLayout; - if (xkbVariant.length > 0) - description = description + '\t' + xkbVariant; - - Util.spawn(['gkbd-keyboard-display', '-l', description]); - }, - _makeEngineShortName: function(engineDesc) { let symbol = engineDesc.get_symbol(); if (symbol && symbol[0]) @@ -493,6 +416,175 @@ const InputSourceIndicator = new Lang.Class({ return false; }, + _getNewInputSource: function(current) { + for (let i in this._inputSources) { + let is = this._inputSources[i]; + if (is.type == current.type && + is.id == current.id) + return is; + } + return this._currentSource; + }, + + _getCurrentWindow: function() { + if (Main.overview.visible) + return Main.overview; + else + return global.display.focus_window; + }, + + _setPerWindowInputSource: function() { + let window = this._getCurrentWindow(); + if (!window) + return; + + if (!window._inputSources) { + window._inputSources = this._inputSources; + window._currentSource = this._currentSource; + } else if (window._inputSources == this._inputSources) { + window._currentSource.activate(); + } else { + window._inputSources = this._inputSources; + window._currentSource = this._getNewInputSource(window._currentSource); + window._currentSource.activate(); + } + }, + + _sourcesPerWindowChanged: function() { + this._sourcesPerWindow = this._settings.get_boolean('per-window'); + + if (this._sourcesPerWindow && this._focusWindowNotifyId == 0) { + this._focusWindowNotifyId = global.display.connect('notify::focus-window', + Lang.bind(this, this._setPerWindowInputSource)); + this._overviewShowingId = Main.overview.connect('showing', + Lang.bind(this, this._setPerWindowInputSource)); + this._overviewHiddenId = Main.overview.connect('hidden', + Lang.bind(this, this._setPerWindowInputSource)); + } else if (!this._sourcesPerWindow && this._focusWindowNotifyId != 0) { + global.display.disconnect(this._focusWindowNotifyId); + this._focusWindowNotifyId = 0; + Main.overview.disconnect(this._overviewShowingId); + this._overviewShowingId = 0; + Main.overview.disconnect(this._overviewHiddenId); + this._overviewHiddenId = 0; + + let windows = global.get_window_actors().map(function(w) { + return w.meta_window; + }); + for (let i = 0; i < windows.length; ++i) { + delete windows[i]._inputSources; + delete windows[i]._currentSource; + } + delete Main.overview._inputSources; + delete Main.overview._currentSource; + } + }, + + _changePerWindowSource: function() { + if (!this._sourcesPerWindow) + return; + + let window = this._getCurrentWindow(); + if (!window) + return; + + window._inputSources = this._inputSources; + window._currentSource = this._currentSource; + }, + + get currentSource() { + return this._currentSource; + }, + + get inputSources() { + return this._inputSources; + }, +}); +Signals.addSignalMethods(InputSourceManager.prototype); + +let _inputSourceManager = null; + +function getInputSourceManager() { + if (_inputSourceManager == null) + _inputSourceManager = new InputSourceManager(); + return _inputSourceManager; +} + +const InputSourceIndicator = new Lang.Class({ + Name: 'InputSourceIndicator', + Extends: PanelMenu.Button, + + _init: function() { + this.parent(0.0, _("Keyboard")); + + this._container = new Shell.GenericContainer(); + this._container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth)); + this._container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight)); + this._container.connect('allocate', Lang.bind(this, this._containerAllocate)); + + this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' }); + this._hbox.add_child(this._container); + this._hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM)); + + this.actor.add_child(this._hbox); + this.actor.add_style_class_name('panel-status-button'); + + this._propSeparator = new PopupMenu.PopupSeparatorMenuItem(); + this.menu.addMenuItem(this._propSeparator); + this._propSection = new PopupMenu.PopupMenuSection(); + this.menu.addMenuItem(this._propSection); + this._propSection.actor.hide(); + + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout)); + + Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated)); + this._sessionUpdated(); + + this._inputSourceManager = getInputSourceManager(); + this._inputSourceManager.connect('sources-changed', Lang.bind(this, this._sourcesChanged)); + this._inputSourceManager.connect('current-source-changed', Lang.bind(this, this._currentSourceChanged)); + this._inputSourceManager.reload(); + }, + + _sessionUpdated: function() { + // re-using "allowSettings" for the keyboard layout is a bit shady, + // but at least for now it is used as "allow popping up windows + // from shell menus"; we can always add a separate sessionMode + // option if need arises. + this._showLayoutItem.actor.visible = Main.sessionMode.allowSettings; + }, + + _sourcesChanged: function() { + let menuIndex = 0; + for (let i in this._inputSourceManager.inputSources) { + let is = this._inputSourceManager.inputSources[i]; + this.menu.addMenuItem(is.menuItem, menuIndex++); + this._container.add_actor(is.indicatorLabel); + } + }, + + _currentSourceChanged: function() { + let nVisibleSources = Object.keys(this._inputSourceManager.inputSources).length; + let newSource = this._inputSourceManager.currentSource; + + if (!newSource || (nVisibleSources < 2 && !newSource.properties)) { + // This source index might be invalid if we weren't able + // to build a menu item for it, so we hide ourselves since + // we can't fix it here. *shrug* + + // We also hide if we have only one visible source unless + // it's an IBus source with properties. + this.menu.close(); + this.actor.hide(); + return; + } + + this.actor.show(); + + this._buildPropSection(newSource.properties); + }, + _buildPropSection: function(properties) { this._propSeparator.actor.hide(); this._propSection.actor.hide(); @@ -510,6 +602,7 @@ const InputSourceIndicator = new Lang.Class({ if (!props) return; + let ibusManager = IBusManager.getIBusManager(); let radioGroup = []; let p; for (let i = 0; (p = props.get(i)) != null; ++i) { @@ -552,13 +645,13 @@ const InputSourceIndicator = new Lang.Class({ if (group[i] == item) { item.setOrnament(PopupMenu.Ornament.DOT); item.prop.set_state(IBus.PropState.CHECKED); - this._ibusManager.activateProperty(item.prop.get_key(), - IBus.PropState.CHECKED); + ibusManager.activateProperty(item.prop.get_key(), + IBus.PropState.CHECKED); } else { group[i].setOrnament(PopupMenu.Ornament.NONE); group[i].prop.set_state(IBus.PropState.UNCHECKED); - this._ibusManager.activateProperty(group[i].prop.get_key(), - IBus.PropState.UNCHECKED); + ibusManager.activateProperty(group[i].prop.get_key(), + IBus.PropState.UNCHECKED); } } })); @@ -570,12 +663,12 @@ const InputSourceIndicator = new Lang.Class({ item.connect('toggled', Lang.bind(this, function() { if (item.state) { item.prop.set_state(IBus.PropState.CHECKED); - this._ibusManager.activateProperty(item.prop.get_key(), - IBus.PropState.CHECKED); + ibusManager.activateProperty(item.prop.get_key(), + IBus.PropState.CHECKED); } else { item.prop.set_state(IBus.PropState.UNCHECKED); - this._ibusManager.activateProperty(item.prop.get_key(), - IBus.PropState.UNCHECKED); + ibusManager.activateProperty(item.prop.get_key(), + IBus.PropState.UNCHECKED); } })); break; @@ -584,8 +677,8 @@ const InputSourceIndicator = new Lang.Class({ item = new PopupMenu.PopupMenuItem(prop.get_label().get_text()); item.prop = prop; item.connect('activate', Lang.bind(this, function() { - this._ibusManager.activateProperty(item.prop.get_key(), - item.prop.get_state()); + ibusManager.activateProperty(item.prop.get_key(), + item.prop.get_state()); })); break; @@ -603,80 +696,31 @@ const InputSourceIndicator = new Lang.Class({ } }, - _getNewInputSource: function(current) { - for (let i in this._inputSources) { - let is = this._inputSources[i]; - if (is.type == current.type && - is.id == current.id) - return is; - } - return this._currentSource; - }, - - _getCurrentWindow: function() { - if (Main.overview.visible) - return Main.overview; - else - return global.display.focus_window; - }, - - _setPerWindowInputSource: function() { - let window = this._getCurrentWindow(); - if (!window) - return; - - if (!window._inputSources) { - window._inputSources = this._inputSources; - window._currentSource = this._currentSource; - } else if (window._inputSources == this._inputSources) { - window._currentSource.activate(); - } else { - window._inputSources = this._inputSources; - window._currentSource = this._getNewInputSource(window._currentSource); - window._currentSource.activate(); - } - }, - - _sourcesPerWindowChanged: function() { - this._sourcesPerWindow = this._settings.get_boolean('per-window'); + _showLayout: function() { + Main.overview.hide(); - if (this._sourcesPerWindow && this._focusWindowNotifyId == 0) { - this._focusWindowNotifyId = global.display.connect('notify::focus-window', - Lang.bind(this, this._setPerWindowInputSource)); - this._overviewShowingId = Main.overview.connect('showing', - Lang.bind(this, this._setPerWindowInputSource)); - this._overviewHiddenId = Main.overview.connect('hidden', - Lang.bind(this, this._setPerWindowInputSource)); - } else if (!this._sourcesPerWindow && this._focusWindowNotifyId != 0) { - global.display.disconnect(this._focusWindowNotifyId); - this._focusWindowNotifyId = 0; - Main.overview.disconnect(this._overviewShowingId); - this._overviewShowingId = 0; - Main.overview.disconnect(this._overviewHiddenId); - this._overviewHiddenId = 0; + let source = this._inputSourceManager.currentSource; + let xkbLayout = ''; + let xkbVariant = ''; - let windows = global.get_window_actors().map(function(w) { - return w.meta_window; - }); - for (let i = 0; i < windows.length; ++i) { - delete windows[i]._inputSources; - delete windows[i]._currentSource; + if (source.type == INPUT_SOURCE_TYPE_XKB) { + [, , , xkbLayout, xkbVariant] = KeyboardManager.getXkbInfo().get_layout_info(source.id); + } else if (source.type == INPUT_SOURCE_TYPE_IBUS) { + let engineDesc = IBusManager.getIBusManager().getEngineDesc(source.id); + if (engineDesc) { + xkbLayout = engineDesc.get_layout(); + xkbVariant = ''; } - delete Main.overview._inputSources; - delete Main.overview._currentSource; } - }, - _changePerWindowSource: function() { - if (!this._sourcesPerWindow) + if (!xkbLayout || xkbLayout.length == 0) return; - let window = this._getCurrentWindow(); - if (!window) - return; + let description = xkbLayout; + if (xkbVariant.length > 0) + description = description + '\t' + xkbVariant; - window._inputSources = this._inputSources; - window._currentSource = this._currentSource; + Util.spawn(['gkbd-keyboard-display', '-l', description]); }, _containerGetPreferredWidth: function(container, for_height, alloc) { @@ -685,8 +729,8 @@ const InputSourceIndicator = new Lang.Class({ // for those we don't actually display. let max_min_width = 0, max_natural_width = 0; - for (let i in this._inputSources) { - let is = this._inputSources[i]; + for (let i in this._inputSourceManager.inputSources) { + let is = this._inputSourceManager.inputSources[i]; let [min_width, natural_width] = is.indicatorLabel.get_preferred_width(for_height); max_min_width = Math.max(max_min_width, min_width); max_natural_width = Math.max(max_natural_width, natural_width); @@ -699,8 +743,8 @@ const InputSourceIndicator = new Lang.Class({ _containerGetPreferredHeight: function(container, for_width, alloc) { let max_min_height = 0, max_natural_height = 0; - for (let i in this._inputSources) { - let is = this._inputSources[i]; + for (let i in this._inputSourceManager.inputSources) { + let is = this._inputSourceManager.inputSources[i]; let [min_height, natural_height] = is.indicatorLabel.get_preferred_height(for_width); max_min_height = Math.max(max_min_height, min_height); max_natural_height = Math.max(max_natural_height, natural_height); @@ -717,8 +761,8 @@ const InputSourceIndicator = new Lang.Class({ box.y2 -= box.y1; box.y1 = 0; - for (let i in this._inputSources) { - let is = this._inputSources[i]; + for (let i in this._inputSourceManager.inputSources) { + let is = this._inputSourceManager.inputSources[i]; is.indicatorLabel.allocate_align_fill(box, 0.5, 0.5, false, false, flags); } }